import re
from datetime import datetime as DateTime
from typing import Dict
from typing import List
from typing import NamedTuple
from typing import Optional

from person import anonymize_text
from person import Person
from sanitize import sanitize_html
from templating import render

_datetime_format = "%Y-%m-%d %H:%M"


def _parse_datetime(inp: str) -> Optional[DateTime]:
    try:
        return DateTime.strptime(inp, _datetime_format)
    except ValueError:
        return None


def _format_datetime(inp: Optional[DateTime]) -> str:
    try:
        return inp.strftime(_datetime_format)
    except AttributeError:
        return ""


def _highlight_bracket(match) -> str:
    content = match[1]
    if content == "*":
        return '<span class="the-author">[*]</span>'
    elif content.istitle():
        person = Person.lookup_or_create(content)
        return f'<span class="name" style="color:{person.color}">[{content}]</span>'
    else:
        return f'<span class="bracket">[{content}]</span>'


def highlight_brackets(text: str) -> str:
    return re.sub(r"\[(.+?)\]", _highlight_bracket, text)


with open("templates/quote.html") as file:
    template = file.read()


class Quote(NamedTuple):
    id: str
    author: Person
    text: str
    context: str
    datetime: Optional[DateTime]
    writer: Person
    text_en: str
    context_en: str

    columns = [
        "id",
        "author",
        "text",
        "context",
        "datetime",
        "writer",
        "text_en",
        "context_en",
    ]

    @classmethod
    def from_dict(cls: type, dic: Dict):
        return cls(
            id=dic["id"],
            author=Person.lookup_or_create(dic["author"]),
            text=dic["text"],
            context=dic["context"],
            datetime=_parse_datetime(dic["datetime"]),
            writer=Person.lookup_or_create(dic["writer"]),
        )

    @classmethod
    def from_hlas1(cls: type, hlas1: str):
        for line in hlas1.splitlines():
            symbol = line[0]
            data = line[2:]
            if symbol == "#":
                id = data
            elif symbol == "@":
                author = Person.lookup_or_create(data)
            elif symbol == ">":
                text = data
            elif symbol == "*":
                context = data
            elif symbol == "/":
                datetime = _parse_datetime(data)
            elif symbol == "&":
                writer = Person.lookup_or_create(data)
        return cls(
            id=id,
            author=author,
            text=text,
            context=context,
            datetime=datetime,
            writer=writer,
        )

    @classmethod
    def from_row(cls: type, row):
        id, author, text, context, datetime, writer, text_en, context_en = row
        return cls(
            id,
            Person.lookup_or_create(author),
            text,
            context,
            _parse_datetime(datetime),
            Person.lookup_or_create(writer),
            text_en,
            context_en,
        )

    def to_dict(self, anonymize=True) -> Dict[str, str]:
        return {
            "id": self.id,
            "author": self.author.name if anonymize else self.author.actual_name,
            "text": anonymize_text(self.text) if anonymize else self.text,
            "context": anonymize_text(self.context) if anonymize else self.context,
            "datetime": _format_datetime(self.datetime),
            "writer": self.writer.name,
            "text_en": self.text_en,
            "context_en": self.context_en,
        }

    def to_html(self, language: str) -> str:
        dic = {key: sanitize_html(val) for key, val in self.to_dict().items()}
        dic["bgcolor"] = self.author.bgcolor
        dic["color"] = self.author.color
        dic["edit_link"] = f"edit.py?id={self.id}"
        if language == "english":
            dic["text"] = sanitize_html(self.text_en)
            dic["context"] = sanitize_html(self.context_en)
        elif language == "both":
            dic[
                "text"
            ] += f'<br><span class="english">{sanitize_html(self.text_en)}</span>'
            if self.context_en:
                dic[
                    "context"
                ] += (
                    f'<br><span class="english">{sanitize_html(self.context_en)}</span>'
                )
        dic["text"] = highlight_brackets(dic["text"])
        return render(template, dic)

    def to_hlas1(self) -> str:
        return f"""
# {self.id}
@ {self.author}
> {self.text}
* {self.context}
/ {self.datetime}
& {self.writer}
"""


def parse_hlas1(hlas1: str) -> List[Quote]:
    return [Quote.from_hlas1(par) for par in hlas1.split("\n\n") if par.strip() != ""]
